/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 * Description: Signature Verify CBB Library
 * Author: yangdingfu
 * Create: 2021
 * History: 2021/02/24 new
 */

#include "../cms/cmscbb_crl_compare.h"
#include "cmscbb_sdk.h"
#include "../asn1/cmscbb_asn1_utils.h"
#include "../cmscbb_common/cmscbb_common.h"
#include "../cmscbb_common/cmscbb_list.h"
#include "../x509/cmscbb_x509.h"
#include "../pki/cmscbb_pki.h"

#if CMSCBB_WITHOUT_SECUREC == 0
#include "securec.h"
#endif

#if CMSCBB_SUPPORT_CRL_COMPARE

CVB_STATIC CVB_BOOL IsCertCrlRevovked(const CmscbbCrlToUpdateList* crlList, const CmscbbCrlAddressInfo *crl)
{
    CVB_UINT32 i;
    CVB_UINT32 j;
    for (i = 0; i < MAX_REVOKE_LIST_NUM; i++) {
        CVB_UINT32 revokeCount = crlList->revokeList[i].revokeCount;
        if (revokeCount == 0) {
            continue;
        }
        for (j = 0; j < revokeCount; j++) {
            if (crl->serialNum.snLenth == crlList->revokeList[i].snList[j].snLenth &&
                CmscbbMemCmp(crl->serialNum.sn, crlList->revokeList[i].snList[j].sn, crl->serialNum.snLenth) == 0) {
                return CVB_TRUE;
            }
        }
    }
    return CVB_FALSE;
}

CMSCBB_ERROR_CODE CmscbbAddCertCrlToUpdateList(CmscbbCrlToUpdateList* targeCrlList,
    const CmscbbCrlAddressInfo* toAddCrlAddr, const CmscbbCrlToUpdateList* crlList)
{
    CMSCBB_ERROR_CODE ret;
    CmscbbCrlAddressInfo* resultAddr = CVB_NULL;
    if (targeCrlList->totalCount >= MAX_CRL_SUPPORT + MAX_CERT_SUPPORT) {
        return CMSCBB_ERR_PKI_CRL_INVALID;
    }
    if ((toAddCrlAddr->type == ELEMENT_CERT && targeCrlList->certCount >= MAX_CERT_SUPPORT) ||
        (toAddCrlAddr->type == ELEMENT_CRL && targeCrlList->totalCount - targeCrlList->certCount >= MAX_CRL_SUPPORT)) {
        return CMSCBB_ERR_PKI_CRL_INVALID;
    }
    if (crlList != NULL && IsCertCrlRevovked(crlList, toAddCrlAddr) == CVB_TRUE) {
        return CVB_SUCCESS;
    }
    ret = CmscbbMallocWith0((CVB_VOID**)&resultAddr, sizeof(CmscbbCrlAddressInfo));
    if (CVB_FAILED(ret)) {
        return ret;
    }
    ret = (CMSCBB_ERROR_CODE)memcpy_s(resultAddr, sizeof(CmscbbCrlAddressInfo),
        toAddCrlAddr, sizeof(CmscbbCrlAddressInfo));
    if (CVB_FAILED(ret)) {
        CmscbbFreeWithNullCheck(resultAddr);
        return ret;
    }

    targeCrlList->addressInfoList[targeCrlList->totalCount++] = resultAddr;
    if (resultAddr->type == ELEMENT_CERT) {
        targeCrlList->certCount++;
    }
    return CVB_SUCCESS;
}

CVB_STATIC CmscbbCrlPeriodStat InternalSingleCrlCompare(CVB_INT32 toUpdateCrlNum, CVB_INT32 localCrlNum,
    CVB_INT64 toUpdateUpdateTime, CVB_INT64 localUpdateTime)
{
    if (toUpdateCrlNum > localCrlNum && toUpdateUpdateTime > localUpdateTime) {
        return SCPS_NEW;
    } else if (toUpdateCrlNum < localCrlNum && toUpdateUpdateTime < localUpdateTime) {
        return SCPS_OLD;
    } else if (toUpdateCrlNum == localCrlNum && toUpdateUpdateTime == localUpdateTime) {
        return SCPS_SAME;
    } else {
        return SCPS_MIX;
    }
}

CVB_STATIC CmscbbCrlPeriodStat InternalSingleCertCompare(const CVB_BYTE *toUpdateCertAddr, CVB_UINT32 toUpdateLen,
    const CVB_BYTE *localCertAddr, CVB_UINT32 localLen)
{
    if (toUpdateLen == localLen && CmscbbMemCmp(toUpdateCertAddr, localCertAddr, toUpdateLen) == 0) {
        return SCPS_OLD;
    } else {
        return SCPS_NEW;
    }
}

CVB_STATIC CMSCBB_ERROR_CODE InternalUpdateAddrWithNewer(int type, const CmscbbCrlAddressInfo* toUpdate,
    const CmscbbCrlAddressInfo* local, CmscbbCrlAddressInfo *resultAddr)
{
    CmscbbCrlPeriodStat curState;
    CMSCBB_ERROR_CODE ret;
    if (type == ELEMENT_CRL) {
        curState = InternalSingleCrlCompare(toUpdate->crlNumber, local->crlNumber,
            toUpdate->updateTime, local->updateTime);
    } else {
        curState = InternalSingleCertCompare(toUpdate->crlAddr, toUpdate->length, local->crlAddr, local->length);
    }

    if (curState == SCPS_NEW) {
        ret = (CMSCBB_ERROR_CODE)memcpy_s(resultAddr, sizeof(CmscbbCrlAddressInfo),
            toUpdate, sizeof(CmscbbCrlAddressInfo));
    } else if (curState == SCPS_MIX) {
        ret = CMSCBB_ERR_PKI_CRL_INVALID;
    } else {
        ret = CVB_SUCCESS;
    }
    return ret;
}
CMSCBB_ERROR_CODE CmscbbCrlListCompare(const CmscbbCrlToUpdateList* crlToUpdate,
    const CmscbbCrlToUpdateList* crlOnDevice, CmscbbCrlToUpdateList* resultCrlResult)
{
    CVB_INT i;
    CVB_INT j;
    CVB_BOOL foundIssuer = CVB_FALSE;
    CMSCBB_ERROR_CODE ret;
    for (i  = 0; i < crlToUpdate->totalCount; i++) {
        const CmscbbCrlAddressInfo *toUpdateCrl = crlToUpdate->addressInfoList[i];
        if (IsCertCrlRevovked(crlToUpdate, toUpdateCrl) == CVB_TRUE ||
            IsCertCrlRevovked(crlOnDevice, toUpdateCrl) == CVB_TRUE) {
            continue;
        }
        foundIssuer = CVB_FALSE;
        for (j = 0; j < crlOnDevice->totalCount; j++) {
            const CmscbbCrlAddressInfo *localCrl = crlOnDevice->addressInfoList[j];
            if (localCrl->type != toUpdateCrl->type || CmscbbStrCmp(toUpdateCrl->name, localCrl->name) != 0) {
                continue;
            }

            foundIssuer = CVB_TRUE;
            ret = InternalUpdateAddrWithNewer(localCrl->type, toUpdateCrl, localCrl,
                resultCrlResult->addressInfoList[j]);
            if (CVB_FAILED(ret)) {
                CVB_LOG_ERROR(ret, CVB_NULL);
                return ret;
            }
            break;
        }
        if (foundIssuer != CVB_TRUE) {
            ret = CmscbbAddCertCrlToUpdateList(resultCrlResult, toUpdateCrl, CVB_NULL);
            if (CVB_FAILED(ret)) {
                CVB_LOG_ERROR(ret, CVB_NULL);
                return ret;
            }
        }
    }
    return CVB_SUCCESS;
}

CVB_STATIC CVB_BOOL InterlnalFindUpdateListDuplicateCertCrl(const CmscbbCrlToUpdateList* crlList)
{
    CVB_INT iter;
    /* Traversing CRLs from 0 to N-2 */
    for (iter = 0; iter < crlList->totalCount - 1; ++iter) {
        CmscbbCrlAddressInfo* crl = crlList->addressInfoList[iter];
        CVB_INT iNext;
        /* Traversing CRLs from iter+1 to N-1 */
        for (iNext = iter + 1; iNext < crlList->totalCount; ++iNext) {
            CmscbbCrlAddressInfo* crlNext = crlList->addressInfoList[iNext];
            if (crl->type != crlNext->type) {
                continue;
            }
            /* Name of the CRL publisher before and after the check */
            if (crlNext->type == ELEMENT_CRL && CmscbbStrCmp(crl->name, crlNext->name) == 0) {
                return CVB_TRUE;
            }
            if (crlNext->type == ELEMENT_CERT && CmscbbStrCmp(crl->name, crlNext->name) == 0 &&
                crl->length == crlNext->length && CmscbbMemCmp(crl->crlAddr, crlNext->crlAddr, crl->length) == 0) {
                return CVB_TRUE;
            }
        }
    }
    return CVB_FALSE;
}

CMSCBB_ERROR_CODE CmscbbCheckCrlUpdateList(const CmscbbCrlToUpdateList* updateList)
{
    CVB_INT iter;
    if (updateList->totalCount == 0) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CRL_EMPTY, CVB_NULL);
        return CMSCBB_ERR_PKI_CRL_EMPTY;
    }

    for (iter = 0; iter < updateList->totalCount; iter++) {
        CmscbbCrlAddressInfo* crl = updateList->addressInfoList[iter];
        if (crl->type != ELEMENT_CRL && crl->type != ELEMENT_CERT) {
            return CMSCBB_ERR_CONTEXT_INVALID_PARAM;
        }
    }

    if (InterlnalFindUpdateListDuplicateCertCrl(updateList) == CVB_TRUE) {
        return CMSCBB_ERR_PKI_CRL_DUPLICATE_ISSUER;
    }
    return CVB_SUCCESS;
}

CMSCBB_ERROR_CODE CmscbbSetCrlAddrInfo(CmscbbCrlAddressInfo* addressInfo, const CmscbbX509Crl* crl)
{
    CMSCBB_ERROR_CODE ret;
    CVB_TIME_T updateTime = 0;
    CVB_CHAR *issuer = CVB_NULL;
    CVB_UINT32 issuerLen = 0;

    addressInfo->type = ELEMENT_CRL;
    addressInfo->crlAddr = crl->oriCrlAddr;
    addressInfo->length = crl->crlLength;
    addressInfo->crlNumber = crl->tbsCertList.extensions.crlNumber;
    ret = CmscbbConvertDatetimeToTime(&(crl->tbsCertList.thisUpdateTime), &updateTime);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }
    addressInfo->updateTime = (CVB_INT64)updateTime;
    ret = CmscbbConvertFromX509Name(&(crl->tbsCertList.issuer), &issuer, &issuerLen);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }
    ret = (CMSCBB_ERROR_CODE)strcpy_s(addressInfo->name, MAX_ISSUER_NAME_LENGTH, issuer);
    if (CVB_FAILED(ret)) {
        CmscbbFreeWithNullCheck(issuer);
        return ret;
    }
    CmscbbFreeWithNullCheck(issuer);
    return CVB_SUCCESS;
}

CMSCBB_ERROR_CODE CmscbbAddCertsToUpdateList(CmscbbCrlToUpdateList* result, const LIST_OF(CmscbbX509Cert)* certList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_INT iter = 0;
    CmscbbCrlAddressInfo* addressInfo = CVB_NULL;

    CVB_UINT32 subjectLen = 0;
    for (; iter < (CVB_INT)certList->num; ++iter) {
        CVB_CHAR *subject = CVB_NULL;
        CmscbbX509Cert* cert = certList->data[iter];
        addressInfo = CVB_NULL;
        if (cert == CVB_NULL) {
            continue;
        }
        if (result->certCount >= MAX_CERT_SUPPORT) {
            CVB_LOG_DEBUG(CMSCBB_ERR_CONTEXT_INVALID_PARAM, CVB_NULL);
            return CMSCBB_ERR_CONTEXT_INVALID_PARAM;
        }
        ret = CmscbbMallocWith0((CVB_VOID**)&addressInfo, sizeof(CmscbbCrlAddressInfo));
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        addressInfo->type = ELEMENT_CERT;
        addressInfo->crlAddr = cert->oriCertAddr;
        addressInfo->length = cert->certLength;
        ret = CmscbbConvertFromX509Name(&(cert->toBeSigned.subject), &subject, &subjectLen);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);

        ret = (CMSCBB_ERROR_CODE)strcpy_s(addressInfo->name, MAX_ISSUER_NAME_LENGTH, subject);
        CmscbbFreeWithNullCheck(subject);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);

        ret = (CMSCBB_ERROR_CODE)memcpy_s(addressInfo->serialNum.sn, CMSCBB_MAX_SN_LEN,
            cert->toBeSigned.serialNumber.octs, cert->toBeSigned.serialNumber.len);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        addressInfo->serialNum.snLenth = cert->toBeSigned.serialNumber.len;

        result->addressInfoList[result->totalCount++] = addressInfo;
        result->certCount++;
    }
    return CVB_SUCCESS;
CVB_ERR:
    CmscbbFreeWithNullCheck(addressInfo);
    return ret;
}

/*
 * Prototype    : InternalIsCrlIssuerRevoked
 * Description  : check if the missing crl's issuer is revoked
 * Params
 *   [IN] vrf: verify context
 *   [IN] pciRoot: crl issued by root
 *   [IN] pciMissing: crl which can't found in old crl list.
 * Return Value : TRUE: the missing crl's issuer sn found in revoke list from new root crl;
 *                FALSE: not found
 *   Date              Author     Modification
 *   2016/06/01 10:17  tangzonglei  Create
 */
CVB_STATIC CVB_BOOL InternalIsCrlIssuerRevoked(const CmscbbCrlInfo* ciRoot, const CmscbbCrlInfo* ciMissing)
{
    CVB_INT iter;

    /* find missing issuer sn from root crl's revoke list */
    for (iter = 0; iter < (CVB_INT)ciRoot->revokeList.revokeCount; ++iter) {
        CmscbbSerialNum* revokedSn = ciRoot->revokeList.snList + iter;
        if (revokedSn->snLenth == ciMissing->issuerSn.snLenth &&
            CmscbbMemCmp(revokedSn->sn, ciMissing->issuerSn.sn, ciMissing->issuerSn.snLenth) == 0) {
            return CVB_TRUE;
        }
    }

    /* not found */
    return CVB_FALSE;
}

/*
 * Prototype    : InternalCheckNewCrl
 * Description  : check if the new CRL contains all corresponding CRL in old.
 * Params
 *   [IN] vrf: data for verify context
 *   [IN] newCrlBi: new crl bundle information which contains all in old
 *   [IN] oldCrlBi: old crl bundle information
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 14:54  tangzonglei  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalCheckNewCrl(const CmscbbCrlBundleInfo* newCrlBi,
    const CmscbbCrlBundleInfo* oldCrlBi)
{
    CVB_INT iNew;
    CVB_INT iOld;
    const CmscbbCrlInfo* pciRoot = CVB_NULL;

    /* new CRL bundle should contains all in old */
    for (iOld = 0; iOld < oldCrlBi->crlCount; ++iOld) {
        CVB_BOOL found = CVB_FALSE;
        const CmscbbCrlInfo* psiOld = oldCrlBi->crlInfoList[iOld];
        if (psiOld == CVB_NULL) {
            return CMSCBB_ERR_UNDEFINED;
        }

        for (iNew = 0; iNew < (CVB_INT)newCrlBi->crlCount; ++iNew) {
            const CmscbbCrlInfo* psiNew = newCrlBi->crlInfoList[iNew];
            if (psiNew == CVB_NULL) {
                return CMSCBB_ERR_UNDEFINED;
            }

            /* Finds the CRL issued by the root certificate, which has revocation information for level two CAs */
            if (pciRoot == CVB_NULL && psiNew->revokeList.revokeCount != 0) {
                pciRoot = psiNew;
            }

            if (CmscbbStrCmp(psiNew->issuer, psiOld->issuer) == 0) {
                found = CVB_TRUE;
                break;
            }
        }
        if (found == CVB_FALSE) {
            /* check root CRL's revoke list for missing issuer */
            if (pciRoot != CVB_NULL && InternalIsCrlIssuerRevoked(pciRoot, psiOld) == CVB_TRUE) {
                continue;
            }
            return CMSCBB_ERR_UNDEFINED;
        }
    }

    return CVB_SUCCESS;
}

/*
 * Prototype    : InternalCompareCrlInfo
 * Description  : compare two CRL info to get which is newer
 * Params
 *   [IN] vrf: data for verify context
 *   [IN] psi1: crl info 1
 *   [IN] psi2: crl info 2
 *   [OUT] curState: Results of comparisons,
 *           SCPS_NEW: S1 all CRLs are newer than S2.
 *           SCPS_OLD: S1 all CRLs are older than S2.
 *           SCPS_MIX: Cannot be compared, S1 has a new CRL than S2, and there are older CRLs than S2
 * Return Value : CVB_STATIC CVB_INT32
 *   Date              Author     Modification
 *   2015/11/10 14:56  tangzonglei  Create
 */
CVB_STATIC CVB_INT32 InternalCompareCrlInfo(const CmscbbCrlInfo* psi1, const CmscbbCrlInfo* psi2,
    CmscbbCrlPeriodStat* curState)
{
    if (CmscbbStrCmp(psi1->issuer, psi2->issuer) == 0) {
        CmscbbCrlPeriodStat newState = SCPS_SAME;
        if (psi1->updateTime > psi2->updateTime) {
            newState = SCPS_NEW;
        } else if (psi1->updateTime < psi2->updateTime) {
            newState = SCPS_OLD;
        } else { /* same */
            return 0;
        }

        /* state changed */
        if (*curState != newState) {
            if (*curState == SCPS_SAME) {
                *curState = newState;
            } else {
                *curState = SCPS_MIX;
            }
        }
        return 0;
    }
    return -1;
}

/*
 * Prototype    : InternalCompareIntercrossCrl
 * Description  : Compare two crl bundle, which contains inter-crossed crl list.
 * Params
 *   [IN] vrf: data for verify context
 *   [IN] s1: crl bundle info 1
 *   [IN] s2: crl bundle info 2
 *   [OUT] curState: Results of comparisons,
 *           SCPS_NEW: S1 all CRLs are newer than S2.
 *           SCPS_OLD: S1 all CRLs are older than S2.
 *           SCPS_MIX: Cannot be compared, S1 has a new CRL than S2, and there are older CRLs than S2
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 14:56  tangzonglei  Create
 */
CMSCBB_ERROR_CODE CmscbbCompareBundleIntercrossCrl(const CmscbbCrlBundleInfo* s1, const CmscbbCrlBundleInfo* s2,
    CmscbbCrlPeriodStat* curState)
{
    CMSCBB_ERROR_CODE ret = CVB_SUCCESS;
    CVB_INT iS1;
    CVB_INT iS2;

    for (iS1 = 0; iS1 < s1->crlCount; ++iS1) {
        const CmscbbCrlInfo* psi1 = s1->crlInfoList[iS1];
        if (psi1 == CVB_NULL || psi1->valid != 1) {
            *curState = SCPS_MIX;
            return CMSCBB_ERR_PKI_CRL_INVALID;
        }
    }

    for (iS2 = 0; iS2 < s2->crlCount; ++iS2) {
        const CmscbbCrlInfo* psi2 = s2->crlInfoList[iS2];
        if (psi2 == CVB_NULL || psi2->valid != 1) {
            *curState = SCPS_MIX;
            return CMSCBB_ERR_PKI_CRL_INVALID;
        }
    }

    for (iS1 = 0; iS1 < s1->crlCount; ++iS1) {
        const CmscbbCrlInfo* psi1 = s1->crlInfoList[iS1];

        for (iS2 = 0; iS2 < s2->crlCount; ++iS2) {
            const CmscbbCrlInfo* psi2 = s2->crlInfoList[iS2];

            /* find the CRL which have same issuer with psi1 */
            if (InternalCompareCrlInfo(psi1, psi2, curState) == 0) {
                break;
            }
        }

        if (*curState == SCPS_MIX) {
            break;
        }
    }

    return ret;
}

/*
 * Prototype    : CmscbbFindBundleDuplicateCrlIssuer
 * Description  : To troubleshoot duplicate publishers in the same CRL package
 * Params
 *   [IN] vrf: Validation context
 *   [IN] crlToUpdate: CRLs to be updated
 * Return Value : Cvb_true There is a duplicate publisher; Cvb_false No duplicate publisher
 * Remarks      : Repeat the name of the publisher in the CRL, as suggested by Xiao Hui
 *   Date              Author     Modification
 *   2016/04/28 10:11  tangzonglei  Create
 */
CVB_BOOL CmscbbFindBundleDuplicateCrlIssuer(const CmscbbCrlBundleInfo* crlToUpdate)
{
    CVB_INT iter;
    /* Traversing CRLs from 0 to N-2 */
    for (iter = 0; iter < crlToUpdate->crlCount - 1; ++iter) {
        CmscbbCrlInfo* crl = crlToUpdate->crlInfoList[iter];
        CVB_INT iNext;
        /* Traversing CRLs from iter+1 to N-1 */
        for (iNext = iter + 1; iNext < crlToUpdate->crlCount; ++iNext) {
            CmscbbCrlInfo* crlNext = crlToUpdate->crlInfoList[iNext];
            /* Name of the CRL publisher before and after the check */
            if (CmscbbStrCmp(crl->issuer, crlNext->issuer) == 0) {
                return CVB_TRUE;
            }
        }
    }
    return CVB_FALSE;
}

/*
 * Prototype    : CmscbbCheckBundleCompareResult
 * Description  : Compare two CRL file information which update
 * Params
 *   [IN] crlToUpdate: The object to compare
 *   [IN] crlOnDevice: The object to compare
 *   [OUT] curState: Results of comparisons,
 *           SCPS_NEW: S1 all CRLs are newer than S2.
 *           SCPS_OLD: S1 all CRLs are older than S2.
 *           SCPS_MIX: Cannot be compared, S1 has a new CRL than S2, and there are older CRLs than S2
 * Return Value : return cvb_success correctly, error return error code
 *   Date              Author     Modification
 *   2015/11/09 18:49  tangzonglei  Create
 */
CMSCBB_ERROR_CODE CmscbbCheckBundleCompareResult(const CmscbbCrlBundleInfo *crlToUpdate,
    const CmscbbCrlBundleInfo *crlOnDevice, CmscbbCrlPeriodStat curState)
{
    if (curState == SCPS_NEW) { /* crlToUpdate contains all crlOnDevice */
        if (InternalCheckNewCrl(crlToUpdate, crlOnDevice) != CVB_SUCCESS) {
            return CMSCBB_ERR_PKI_CRL_FAILED_MAPPING;
        }
    } else {
        if (InternalCheckNewCrl(crlOnDevice, crlToUpdate) != CVB_SUCCESS) {
            return CMSCBB_ERR_PKI_CRL_FAILED_MAPPING;
        }
    }
    return CVB_SUCCESS;
}

/* Get issuer name */
CVB_STATIC CVB_VOID InternalGetCrlIssuerName(CmscbbCrlInfo* crlInfo, const CmscbbX509Crl* crl)
{
    CMSCBB_ERROR_CODE ret;

    CVB_CHAR* issuer = CVB_NULL;
    CVB_UINT32 issuerLen = 0;

    ret = CmscbbConvertFromX509Name(&(crl->tbsCertList.issuer), &issuer, &issuerLen);
    if (ret == CVB_SUCCESS) {
        ret = (CMSCBB_ERROR_CODE)strcpy_s(crlInfo->issuer, MAX_ISSUER_NAME_LENGTH, issuer);
        if (CVB_FAILED(ret)) {
            CVB_LOG_WARNING(ret, CVB_NULL);
        }
    }
    CmscbbFreeWithNullCheck(issuer);
}

CMSCBB_ERROR_CODE CmscbbCopyRevokeList(CmscbbCrlToUpdateList *result, CVB_INT *revokeIter,
    const CmscbbCrlInfo *crlInfo)
{
    CMSCBB_ERROR_CODE ret = CVB_SUCCESS;
    CmscbbSerialNum* serialNum = CVB_NULL;
    CVB_UINT32 revokeCount = crlInfo->revokeList.revokeCount;
    if (revokeCount != 0) {
        ret = CmscbbMallocWith0((CVB_VOID**)&serialNum, revokeCount * sizeof(CmscbbSerialNum));
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        ret = (CMSCBB_ERROR_CODE)memcpy_s(serialNum, revokeCount * sizeof(CmscbbSerialNum),
            crlInfo->revokeList.snList, revokeCount * sizeof(CmscbbSerialNum));
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        CVB_GOTO_ERR_WITH_LOG_IF(*revokeIter >= MAX_REVOKE_LIST_NUM, CMSCBB_ERR_SYS_LIST_OVERFLOW)
        result->revokeList[*revokeIter].snList = serialNum;
        result->revokeList[*revokeIter].revokeCount = revokeCount;
        (*revokeIter)++;
    }
    return ret;
CVB_ERR:
    CmscbbFreeWithNullCheck(serialNum);
    return ret;
}

CVB_VOID CmscbbCrlInfoFree(CmscbbCrlInfo *crlInfo)
{
    if (crlInfo == CVB_NULL) {
        return;
    }
    CmscbbFreeWithNullCheck(crlInfo->revokeList.snList);
    crlInfo->revokeList.snList = CVB_NULL;
    CmscbbFreeWithNullCheck((CVB_VOID*)crlInfo);
}

#if CMSCBB_FOR_WIRELESS
static CMSCBB_ERROR_CODE InternalCheckIssuerIsselfSigned(CMSCBB_VRF_CTX ctx, const CVB_CHAR *name, CVB_BOOL *selfSigned)
{
    LIST_OF(CmscbbX509Cert)* certList = NULL;
    CVB_UINT32 iter;
    CMSCBB_ERROR_CODE ret;

    ret = CmscbbGetCertAndCrlList(ctx, &certList, NULL);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }
    for (iter = 0; iter < certList->num; ++iter) {
        CmscbbX509Cert* cert = certList->data[iter];
        CVB_BOOL isSelfSigned = CVB_FALSE;
        CVB_CHAR* subject = CVB_NULL;
        CVB_UINT32 subjectLen = 0;
        if (cert == CVB_NULL) {
            continue;
        }
        ret = CmscbbConvertFromX509Name(&(cert->toBeSigned.subject), &subject, &subjectLen);
        if (ret != CVB_SUCCESS) {
            return ret;
        }

        ret = (CMSCBB_ERROR_CODE)CmscbbStrCmp(name, subject);
        CmscbbFreeWithNullCheck(subject);
        if (ret != 0) {
            continue;
        }

        ret = CmscbbX509IsSelfSigned(cert, &isSelfSigned);
        if (CVB_FAILED(ret)) {
            CVB_LOG_ERROR(ret, "Failed to check self sign for certificate.");
            return ret;
        }
        if (isSelfSigned == CVB_TRUE) {
            *selfSigned = isSelfSigned;
            return CVB_SUCCESS;
        }
    }
    return ret;
}

static CMSCBB_ERROR_CODE InternalCheckCrlHasIssuer(CMSCBB_VRF_CTX ctx, CmscbbCrlToUpdateList* crlResult)
{
    CVB_INT32 iter = 0;
    CMSCBB_ERROR_CODE ret = CVB_SUCCESS;
    for (; iter < crlResult->totalCount; iter++) {
        CmscbbCrlAddressInfo *addInfo = crlResult->addressInfoList[iter];
        CVB_INT32 iterIn = 0;
        CVB_BOOL found = CVB_FALSE;
        CVB_BOOL selfSigned = CVB_FALSE;

        if (addInfo->type == ELEMENT_CERT) {
            continue;
        }
        for (; iterIn < crlResult->totalCount; iterIn++) {
            CmscbbCrlAddressInfo *certInfo = crlResult->addressInfoList[iterIn];
            if (certInfo->type == ELEMENT_CRL) {
                continue;
            }

            if (CmscbbStrCmp(addInfo->name, certInfo->name) == 0) {
                found = CVB_TRUE;
                break;
            }
        }
        if (found == CVB_FALSE) {
            ret = InternalCheckIssuerIsselfSigned(ctx, addInfo->name, &selfSigned);
            if (ret != CVB_SUCCESS || selfSigned != CVB_TRUE) {
                CVB_LOG_ERROR(CMSCBB_ERR_PKI_CERT_NOT_FOUND, "The issuer certificate of the CRL is not found.");
                return CMSCBB_ERR_PKI_CERT_NOT_FOUND;
            }
            if (iter != 0) {
                crlResult->addressInfoList[iter] = crlResult->addressInfoList[0];
                crlResult->addressInfoList[0] = addInfo;
            }
        }
    }
    return ret;
}

static CMSCBB_ERROR_CODE InternalCheckCrlResult(const LIST_OF(CmscbbCertNameInfo) *certList,
    CmscbbCrlToUpdateList* crlResult)
{
    CVB_UINT32 iter = 0;
    if (crlResult->totalCount == 0) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CRL_EMPTY, "No CRL is obtained.");
        return CMSCBB_ERR_PKI_CRL_EMPTY;
    }
    for (; iter < certList->num; iter++) {
        CmscbbCertNameInfo *certInfo = certList->data[iter];
        CVB_INT32 iterIn = 0;
        CVB_BOOL found = CVB_FALSE;
        for (; iterIn < crlResult->totalCount; iterIn++) {
            CmscbbCrlAddressInfo *crlInfo = crlResult->addressInfoList[iterIn];
            if (crlInfo->type == ELEMENT_CERT) {
                continue;
            }
            if (CmscbbStrCmp(certInfo->issuerName, crlInfo->name) == 0) {
                found = CVB_TRUE;
                break;
            }
        }
        if (found == CVB_FALSE) {
            CVB_LOG_ERROR(CMSCBB_ERR_PKI_CERT_NO_CRL, "The CRL corresponding to the certificate is not obtained.");
            return CMSCBB_ERR_PKI_CERT_NO_CRL;
        }
    }

    return CVB_SUCCESS;
}

static CVB_BOOL InternalIsSignatureNeed(const CmscbbCrlAddressInfo *addr, const LIST_OF(CmscbbCertNameInfo) *certList)
{
    CVB_UINT32 iter = 0;
    for (; iter < certList->num; iter++) {
        const CmscbbCertNameInfo* addressInfo = certList->data[iter];
        if (addr->type == ELEMENT_CERT && CmscbbStrCmp(addr->name, addressInfo->subjectName) == 0) {
            return CVB_TRUE;
        }
        if (addr->type == ELEMENT_CRL && CmscbbStrCmp(addr->name, addressInfo->issuerName) == 0) {
            return CVB_TRUE;
        }
    }
    return CVB_FALSE;
}

CMSCBB_ERROR_CODE CmscbbObtainRelatedCrl(CMSCBB_VRF_CTX ctx, const CmscbbCrlToUpdateList *crlInfo,
    const LIST_OF(CmscbbCertNameInfo) *certList, CmscbbCrlToUpdateList** crlResult)
{
    CMSCBB_ERROR_CODE ret;
    CVB_UINT32 iter = 0;
    CmscbbCrlToUpdateList* tmpCrlResult = NULL;
    ret = CmscbbMallocWith0((CVB_VOID**)&tmpCrlResult, sizeof(CmscbbCrlToUpdateList));
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);
    for (; iter < (CVB_UINT32)crlInfo->totalCount; iter++) {
        CVB_BOOL status = InternalIsSignatureNeed(crlInfo->addressInfoList[iter], certList);
        if (status == CVB_TRUE) {
            ret = CmscbbAddCertCrlToUpdateList(tmpCrlResult, crlInfo->addressInfoList[iter], CVB_NULL);
            CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        }
    }
    ret = InternalCheckCrlResult(certList, tmpCrlResult);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);
    ret = InternalCheckCrlHasIssuer(ctx, tmpCrlResult);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);
    *crlResult = tmpCrlResult;
    return ret;
CVB_ERR:
    CmscbbCrlUpdateListFree(tmpCrlResult);
    return ret;
}

static CMSCBB_ERROR_CODE InternalGetCertInfo(CmscbbCertNameInfo *certInfo, CmscbbX509Cert *cert)
{
    CMSCBB_ERROR_CODE ret;
    CVB_CHAR* issuer = CVB_NULL;
    CVB_CHAR* subject = CVB_NULL;
    CVB_UINT32 issuerLen = 0;
    CVB_UINT32 subjectLen = 0;

    ret = CmscbbConvertFromX509Name(&(cert->toBeSigned.issuer), &issuer, &issuerLen);
    if (ret != CVB_SUCCESS) {
        return ret;
    }
    ret = (CMSCBB_ERROR_CODE)strcpy_s(certInfo->issuerName, MAX_ISSUER_NAME_LENGTH, issuer);
    if (CVB_FAILED(ret)) {
        CVB_LOG_WARNING(ret, CVB_NULL);
        CmscbbFreeWithNullCheck(issuer);
        return ret;
    }
    ret = CmscbbConvertFromX509Name(&(cert->toBeSigned.subject), &subject, &subjectLen);
    if (ret == CVB_SUCCESS) {
        ret = (CMSCBB_ERROR_CODE)strcpy_s(certInfo->subjectName, MAX_ISSUER_NAME_LENGTH, subject);
        if (CVB_FAILED(ret)) {
            CVB_LOG_WARNING(ret, CVB_NULL);
        }
    }
    CmscbbFreeWithNullCheck(issuer);
    CmscbbFreeWithNullCheck(subject);
    return ret;
}

CMSCBB_ERROR_CODE CmscbbGetCertNameInfo(const LIST_OF(CmscbbX509Cert)* certs, LIST_OF(CmscbbCertNameInfo)* certList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_UINT32 iter = 0;
    CmscbbCertNameInfo *certInfo = NULL;
    for (; iter < certs->num; iter++) {
        certInfo = NULL;
        ret = CmscbbMallocWith0((void **)&certInfo, sizeof(CmscbbCertNameInfo));
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        ret = InternalGetCertInfo(certInfo, certs->data[iter]);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        ret = CMSCBB_LIST_ADD(certList, certInfo);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
    }
    return CVB_SUCCESS;
CVB_ERR:
    CmscbbFreeWithNullCheck(certInfo);
    return ret;
}
#endif /* CMSCBB_FOR_WIRELESS */

CVB_VOID CmscbbCrlBaseInfoFree(CmscbbCrlBaseInfo* crlInfo)
{
    if (crlInfo == CVB_NULL) {
        return;
    }
    CmscbbFreeWithNullCheck(crlInfo->issuerName);
    crlInfo->issuerName = CVB_NULL;
    CmscbbFreeWithNullCheck(crlInfo);
    return;
}

CVB_VOID CmscbbCertBaseInfoFree(CmscbbCertBaseInfo* certInfo)
{
    if (certInfo == CVB_NULL) {
        return;
    }
    CmscbbFreeWithNullCheck(certInfo->issuerName);
    CmscbbFreeWithNullCheck(certInfo->subjectName);
    certInfo->issuerName = CVB_NULL;
    certInfo->subjectName = CVB_NULL;
    CmscbbFree(certInfo);
    return;
}

/*
 * Prototype    : InternalGetCertValidity
 * Description  : Get the Validity of X509 cert
 * Params
 *   [IN] cert: X509 cert
 *   [OUT] notBefore: the notBefore of X509 cert
 *   [OUT] notAfter: the notAfter of X509 cert
 * Return Value : CVB_STATIC CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2021/10/25 11:05  wangqinyu  Create
 */
CVB_STATIC CMSCBB_ERROR_CODE InternalGetCertValidity(const CmscbbX509Cert* cert, CVB_INT64* notBefore,
    CVB_INT64* notAfter)
{
    CMSCBB_ERROR_CODE ret;
    CVB_TIME_T time = 0;
    ret = CmscbbConvertDatetimeToTime(&cert->toBeSigned.validity.notBefore, &time);
    if (ret != CVB_SUCCESS) {
        return ret;
    }
    *notBefore = (CVB_INT64)time;

    ret = CmscbbConvertDatetimeToTime(&cert->toBeSigned.validity.notAfter, &time);
    if (ret != CVB_SUCCESS) {
        return ret;
    }
    *notAfter = (CVB_INT64)time;

    return CVB_SUCCESS;
}

CVB_STATIC CMSCBB_ERROR_CODE InternalGetReadableName(const CmscbbX509Name* name, CVB_CHAR** readableName,
    CVB_UINT32 *readableNameLen)
{
    CMSCBB_ERROR_CODE ret;
    CVB_CHAR* tmpName = CVB_NULL;
    CVB_UINT32 tmpNameLen = 0;

    ret = CmscbbConvertFromX509Name(name, &tmpName, &tmpNameLen);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    *readableName = CVB_NULL;
    ret = CmscbbMallocWith0((CVB_VOID**)readableName, tmpNameLen + 1);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    ret = (CMSCBB_ERROR_CODE)strcpy_s(*readableName, tmpNameLen + 1, tmpName);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);
    *readableNameLen = tmpNameLen + 1;

CVB_ERR:
    if (CVB_FAILED(ret)) {
        CmscbbFreeWithNullCheck(*readableName);
    }
    CmscbbFreeWithNullCheck(tmpName);
    return ret;
}

#define BYTES_OF_COORDINATES 2
CVB_STATIC CMSCBB_ERROR_CODE InternalSetCertInfo(CmscbbCertBaseInfo* certInfo, const CmscbbX509Cert* cert)
{
    CMSCBB_ERROR_CODE ret;
    CmscbbAoids encAlgo;
    CmscbbAoids encAoid;

    ret = InternalGetCertValidity(cert, &certInfo->notBefore, &certInfo->notAfter);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    encAlgo = CmscbbFindAoid(&cert->algorithm.algorithm);
    if (encAlgo == AOID_UNKNOWN) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CERT_SIG_ALGO, CVB_NULL);
        return CMSCBB_ERR_PKI_CERT_SIG_ALGO;
    }
    certInfo->algorithm = (CVB_INT32)encAlgo;

    ret = InternalGetReadableName(&cert->toBeSigned.subject, &certInfo->subjectName, &certInfo->subjectLength);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    ret = InternalGetReadableName(&cert->toBeSigned.issuer, &certInfo->issuerName, &certInfo->issuerLength);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    ret = (CMSCBB_ERROR_CODE)memcpy_s(certInfo->serialNum.sn, CMSCBB_MAX_SN_LEN,
        cert->toBeSigned.serialNumber.octs, cert->toBeSigned.serialNumber.len);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }
    certInfo->serialNum.snLenth = cert->toBeSigned.serialNumber.len;
    encAoid = CmscbbGetEncAoidFromSign(&cert->algorithm.algorithm);
    if (encAoid == AOID_RSA || encAoid == AOID_RSASSAPSS) {
        certInfo->publicKeyLength = (CVB_UINT64)cert->toBeSigned.subjectPubKey.subjectPublicKey.rsaPubKey.modules.len *
            BIT_COUNT_OF_BYTE;
    } else if (encAoid == AOID_ECDSA) {
        /* ref RFC5480
        The first octet of the OCTET STRING indicates whether the key is compressed or uncompressed.
        The uncompressed form is indicated by 0x04 and
        the compressed form is indicated by either 0x02 or 0x03.
        The public key MUST be rejected if any other value is included in the first octet. */
        certInfo->publicKeyLength = (CVB_UINT64)(cert->toBeSigned.subjectPubKey.eccPubKey.len - 1) /
            BYTES_OF_COORDINATES * BIT_COUNT_OF_BYTE;
    } else {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CERT_SIG_ALGO, CVB_NULL);
        return CMSCBB_ERR_PKI_CERT_SIG_ALGO;
    }

    return CVB_SUCCESS;
}

CMSCBB_ERROR_CODE CmscbbAddCertsInfoToList(CmscbbCrlCertInfoList* result, const LIST_OF(CmscbbX509Cert)* certList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_INT iter = 0;
    CmscbbCertBaseInfo* certInfo = CVB_NULL;

    for (; iter < (CVB_INT)certList->num; ++iter) {
        CmscbbX509Cert* cert = certList->data[iter];
        if (cert == CVB_NULL) {
            continue;
        }
        if (result->certCount >= MAX_CERT_SUPPORT) {
            CVB_LOG_ERROR(CMSCBB_ERR_CONTEXT_INVALID_PARAM, CVB_NULL);
            return CMSCBB_ERR_CONTEXT_INVALID_PARAM;
        }
        certInfo = CVB_NULL;
        ret = CmscbbMallocWith0((CVB_VOID**)&certInfo, sizeof(CmscbbCertBaseInfo));
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);

        ret = InternalSetCertInfo(certInfo, cert);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);

        result->certInfoList[result->certCount++] = certInfo;
    }
    return CVB_SUCCESS;
CVB_ERR:
    CmscbbCertBaseInfoFree(certInfo);
    return ret;
}

CVB_STATIC CMSCBB_ERROR_CODE InternalGetCrlUpdateTime(const CmscbbX509Crl* crl, CVB_INT64* thisUpdateTime,
    CVB_INT64* nextUpdateTime)
{
    CMSCBB_ERROR_CODE ret;
    CVB_TIME_T time = 0;
    ret = CmscbbConvertDatetimeToTime(&crl->tbsCertList.thisUpdateTime, &time);
    if (ret != CVB_SUCCESS) {
        return ret;
    }
    *thisUpdateTime = (CVB_INT64)time;

    ret = CmscbbConvertDatetimeToTime(&crl->tbsCertList.nextUpdateTime, &time);
    if (ret != CVB_SUCCESS) {
        return ret;
    }
    *nextUpdateTime = (CVB_INT64)time;

    return CVB_SUCCESS;
}

CVB_STATIC CMSCBB_ERROR_CODE InternalSetCrlInfo(CmscbbCrlBaseInfo* crlInfo, const CmscbbX509Crl* crl)
{
    CMSCBB_ERROR_CODE ret;
    CmscbbAoids encAlgo;

    crlInfo->crlNumber = crl->tbsCertList.extensions.crlNumber;
    encAlgo = CmscbbFindAoid(&crl->algorithm.algorithm);
    if (encAlgo == AOID_UNKNOWN) {
        CVB_LOG_ERROR(CMSCBB_ERR_PKI_CRL_SIG_ALGO, CVB_NULL);
        return CMSCBB_ERR_PKI_CRL_SIG_ALGO;
    }
    crlInfo->algorithm = (CVB_INT32)encAlgo;
    ret = InternalGetCrlUpdateTime(crl, &crlInfo->thisUpdateTime, &crlInfo->nextUpdateTime);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }
    ret = InternalGetReadableName(&crl->tbsCertList.issuer, &crlInfo->issuerName, &crlInfo->issuerLength);
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    return CVB_SUCCESS;
}


CMSCBB_ERROR_CODE CmscbbAddCrlsInfoToList(CmscbbCrlCertInfoList* result, const LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_INT iter = 0;
    CmscbbCrlBaseInfo* crlInfo = CVB_NULL;

    for (; iter < (CVB_INT)crlList->num; ++iter) {
        CmscbbX509Crl* crl = crlList->data[iter];
        crlInfo = CVB_NULL;
        if (crl == CVB_NULL) {
            continue;
        }
        if (result->crlCount >= MAX_CRL_SUPPORT) {
            CVB_LOG_ERROR(CMSCBB_ERR_CONTEXT_INVALID_PARAM, CVB_NULL);
            return CMSCBB_ERR_CONTEXT_INVALID_PARAM;
        }
        ret = CmscbbMallocWith0((CVB_VOID**)&crlInfo, sizeof(CmscbbCrlBaseInfo));
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);
        ret = InternalSetCrlInfo(crlInfo, crl);
        CVB_GOTO_ERR_IF_FAIL_LOG(ret);

        result->crlInfoList[result->crlCount++] = crlInfo;
    }
    return CVB_SUCCESS;
CVB_ERR:
    CmscbbCrlBaseInfoFree(crlInfo);
    return ret;
}


/*
 * Prototype    : InternalGetCrlInfo
 * Description  : get information from CRL
 * Params
 *   [IN] vrf: data for verify context
 *   [IN] crl: X509 crl
 *   [OUT] crlInfo: crl information
 * Return Value : CMSCBB_ERROR_CODE
 *   Date              Author     Modification
 *   2015/11/10 14:53  tangzonglei  Create
 */
CMSCBB_ERROR_CODE CmscbbGetCrlInfo(CmscbbVrf* vrf, const CmscbbX509Crl* crl, CmscbbCrlInfo** crlInfo)
{
    CMSCBB_ERROR_CODE ret;
    CmscbbCrlInfo* info = CVB_NULL;

    *crlInfo = CVB_NULL;
    ret = CmscbbMallocWith0((CVB_VOID**)&info, sizeof(CmscbbCrlInfo));
    if (CVB_FAILED(ret)) {
        CVB_LOG_ERROR(ret, CVB_NULL);
        return ret;
    }

    info->valid = CVB_FALSE;
    InternalGetCrlIssuerName(info, crl);

    ret = InternalGetCrlUpdateTime(crl, &info->updateTime, &info->validUntil);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    /* get verify info */
    ret = CmscbbGetCrlIsAuthored(vrf, info, crl);
    CVB_GOTO_ERR_IF_FAIL_LOG(ret);

    *crlInfo = info;
    return CVB_SUCCESS;

CVB_ERR:
    CmscbbCrlInfoFree(info);
    return ret;
}

CVB_VOID CmscbbUpdateCrlBundle(CmscbbVrf* vrf, CmscbbCrlBundleInfo* result,
    const LIST_OF(CmscbbX509Crl)* crlList)
{
    CMSCBB_ERROR_CODE ret;
    CVB_INT iter = 0;
    CVB_INT maxLoops = (CVB_INT)(crlList->num < MAX_CRL_SUPPORT ? crlList->num : MAX_CRL_SUPPORT);

    result->st_size = sizeof(CmscbbCrlBundleInfo);
    result->crlCount = 0;
    for (; iter < maxLoops; ++iter) {
        CmscbbCrlInfo* crlInfo = CVB_NULL;
        CmscbbX509Crl* crl = crlList->data[iter];
        if (crl == CVB_NULL) {
            continue;
        }
        ret = CmscbbGetCrlInfo(vrf, crl, &crlInfo);
        if (CVB_FAILED(ret)) {
            continue;
        }
        if (crlInfo != CVB_NULL) {
            result->crlInfoList[result->crlCount++] = crlInfo;
        }
    }

    return;
}

#endif /* CMSCBB_SUPPORT_CRL_COMPARE */
